﻿
using AForge.Video.DirectShow;
using Infrastructure.Computer;
using Infrastructure.FileOperate;
using Infrastructure.Image;
using Infrastructure.Web;
using AForge;
using AForge.Controls;
using AForge.Imaging;
using AForge.Video;
using MyData.ApiDto;
using MyData.Dto;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using VideoNet.Common;
using System.Runtime.InteropServices;

namespace VideoNet
{
    public partial class Camera : Form
    {
        [DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
        public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);

        float openDoorTime = 5;
        string imeiNum = "";
        string dicPath = "";
        string comPort = "COM1";
        bool needClose = false;
        bool needRestart = false;
        delegate void SetVisible();
        IntPtr ptr1 = IntPtr.Zero;
        CZCompare compare;
        delegate void delegateRefresh();
        DateTime recordTime = DateTime.Now;
        bool doorStatus = false;
        byte[] OpenCommand = new byte[4] { 0xA0, 0x01, 0x01, 0xA2 };
        byte[] CloseCommand = new byte[4] { 0xA0, 0x01, 0x00, 0xA1 };
        List<CZUserInfo> userList = new List<CZUserInfo>(4);
        List<CZUserInfo> findList = new List<CZUserInfo>();
        MobileLoginOput deviceInfo = null;
        public Camera()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;
            this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
            this.UpdateStyles();
            this.Load += Video_Load;
            this.SizeChanged += Video_SizeChanged;
            this.FormClosing += Camera_FormClosing;
        }
        private void Camera_FormClosing(object sender, FormClosingEventArgs e)
        {
            needClose = true;
            Thread.Sleep(200);
            if (videoSource1 != null && videoSource1.IsRunning)
            {
                videoSource1.SignalToStop();
                videoSource1.WaitForStop();
            }
            if (videoSource2 != null && videoSource2.IsRunning)
            {
                videoSource2.SignalToStop();
                videoSource2.WaitForStop();
            }
            PortHelper.SendCommand(comPort, OpenCommand);

            Process.GetCurrentProcess().Kill();
            System.Environment.Exit(0);
        }

        private void Video_SizeChanged(object sender, EventArgs e)
        {
            float[] scale = (float[])Tag;
            int i = 2;
            if (scale == null)
                return;
            foreach (Control ctrl in this.Controls)
            {
                ctrl.Left = (int)(Size.Width * scale[i++]);
                ctrl.Top = (int)(Size.Height * scale[i++]);
                ctrl.Width = (int)(Size.Width / (float)scale[0] * ((Size)ctrl.Tag).Width);
                ctrl.Height = (int)(Size.Height / (float)scale[1] * ((Size)ctrl.Tag).Height);
                //每次使用的都是最初始的控件大小，保证准确无误。
            }
        }
        string ipaddress = "";
        int port;

        FilterInfoCollection videoDevices;
        private VideoCaptureDevice videoSource1;
        private VideoCaptureDevice videoSource2;

        private void Video_Load(object sender, EventArgs e)
        {
            initWindows();
            VideoUnit();

            dicPath = AppDomain.CurrentDomain.BaseDirectory + @"/Images";
            if (!System.IO.Directory.Exists(dicPath))
            {
                System.IO.Directory.CreateDirectory(dicPath);
            }
            try
            {
                port = 8089;
                int.TryParse(ConfigurationManager.AppSettings["Port"].ToString(), out port);
                ipaddress = ComputerHelper.GetIPAddress();
                LoginDevice();
                comPort = ConfigurationManager.AppSettings["PortCom"].ToString();
                compare = new CZCompare();
                PortHelper.SendCommand(comPort, CloseCommand);
                SetTitle set = new SetTitle(setTitle);
                this.Invoke(set, new object[] { "关" });
                Task.Run(() => { DoWork(); });
                System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
                timer.Interval = 3000;
                timer.Tick += Timer_Tick;
                timer.Start();
                Task.Run(() =>
                {
                    IPAddress ip = IPAddress.Parse(ipaddress);
                    IPEndPoint ipe = new IPEndPoint(ip, port);//把ip和端口转化为IPEndPoint实例
                    Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个Socket
                    server.Bind(ipe);//绑定2000端口
                    server.Listen(0);//开始监听
                    Socket temp = null;
                    while (!needClose)
                    {
                        temp = server.Accept();//为新建连接创建新的Socket。
                        string recvStr = "";
                        byte[] recvBytes = new byte[1024];
                        int bytes;
                        bytes = temp.Receive(recvBytes, recvBytes.Length, 0);//从客户端接受信息
                        recvStr += Encoding.UTF8.GetString(recvBytes, 0, bytes);
                        if (recvStr == "OK")
                        {
                            needRestart = true;
                        }
                        string sendStr = "";
                        byte[] bs = Encoding.UTF8.GetBytes(sendStr);
                        temp.Send(bs, bs.Length, 0);//返回客户端成功信息
                        temp.Close();
                        GC.Collect();
                    }
                    server.Close();
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            DateTime now = DateTime.Now;
            if (doorStatus && (now - recordTime).TotalSeconds > openDoorTime)
            {
                PortHelper.SendCommand(comPort, CloseCommand);
                doorStatus = false;
                pictureBox1.Image = null;
                SetTitle set = new SetTitle(setTitle);
                this.Invoke(set, new object[] { "关" });
                image = "";
                userList.Clear();
            }
            if (now.Minute % 5 == 0 && now.Second == 0)
            {
                LoginDevice();
                if (now.Hour < deviceInfo.DayStart || now.Hour > deviceInfo.DayEnd)
                {
                    similar = deviceInfo.NightSimilar;
                }
                else
                {
                    similar = deviceInfo.Similar;
                }
            }
          
        }

        void VideoUnit()
        {
            videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            if (videoDevices.Count == 0)
            {
                MessageBox.Show("未找到摄像头");
                Application.Exit();
            }
            imeiNum = ComputerHelper.GetCPUID();
            if (videoSource1 != null && videoSource1.IsRunning)
            {
                videoSource1.SignalToStop();
                videoSource1.WaitForStop();
            }
            videoSource1 = new VideoCaptureDevice(videoDevices[0].MonikerString);
            var sizes1 = videoSource1.VideoCapabilities.OrderByDescending(c => c.FrameSize.Width * c.FrameSize.Height).ToList();
            videoSource1.VideoResolution = sizes1[1];
            videoSourcePlayer1.VideoSource = videoSource1;
            videoSourcePlayer1.Start();
            if (videoDevices.Count >= 2)
            {
                if (videoSource2 != null && videoSource2.IsRunning)
                {
                    videoSource2.SignalToStop();
                    videoSource2.WaitForStop();
                }
                videoSource2 = new VideoCaptureDevice(videoDevices[1].MonikerString);
                var sizes2 = videoSource2.VideoCapabilities.OrderByDescending(c => c.FrameSize.Width * c.FrameSize.Height).ToList();
                videoSource2.VideoResolution = sizes2[1];
                videoSourcePlayer2.VideoSource = videoSource2;
                videoSourcePlayer2.Start();
            }
        }
        Bitmap bitmap;
        delegate void RestartVideo();
        float similar = 0.75f;
        private void DoWork()
        {
            GetUserInit();
            Rectangle[] rectangles;
            DateTime now;
            while (!needClose)
            {
                try
                {
                    now = DateTime.Now;
                    if (videoSource1 != null)
                    {
                        bitmap = videoSourcePlayer1.GetCurrentVideoFrame();
                        if (bitmap != null)
                        {
                            rectangles = compare.FindFace(bitmap);
                            if (rectangles.Length > 0)
                            {
                                DoFindPerson(bitmap, rectangles, similar);
                            }
                            bitmap.Dispose();
                            rectangles = null;
                        }
                    }
                    Thread.Sleep(200);
                    if (videoSource2 != null)
                    {
                        bitmap = videoSourcePlayer2.GetCurrentVideoFrame();
                        if (bitmap != null)
                        {
                            rectangles = compare.FindFace(bitmap);
                            if (rectangles.Length > 0)
                            {
                                DoFindPerson(bitmap, rectangles, similar);
                            }
                            bitmap.Dispose();
                            rectangles = null;
                        }
                    }

                    if (needRestart)
                    {
                        needRestart = false;
                        GetUserInit();
                        LoginDevice();
                    }
                    Thread.Sleep(200);
                    Application.DoEvents();
                    ClearMemory();
                }
                catch (Exception ex)
                {
                    FileHelper.WriteFile("D:/1.txt", ex.Message);
                }
            }
        }
      
        /// <summary>
        /// 释放内存
        /// </summary>
        public static void ClearMemory()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
            }
        }
        void LoginDevice()
        {
            MobileLoginInput loginModel = new MobileLoginInput() { ImeiNum = imeiNum, Ip = ipaddress, Port = port };
            AjaxResult<MobileLoginOput> loginResult = WWebClientHelper.HttpPost<AjaxResult<MobileLoginOput>>(WWebClientHelper.LoginApiString, WWebClientHelper.GetJson<MobileLoginInput>(loginModel));
            deviceInfo = loginResult.data;
            openDoorTime = deviceInfo.Duration;
            loginModel = null;
            loginResult = null;
        }
        delegate void SetTitle(string str);
        void setTitle(string str)
        {
            this.Text = "人脸识别————" + str;
        }
        string image = "";
        List<float> similars;
        void DoFindPerson(Bitmap bitmap, Rectangle[] recs, float similar)
        {
            try
            {
                similars = new List<float>();
                findList = compare.CheckFaces(bitmap, similar, recs, ref similars);
                if (findList.Count == 0) return;
                if (!doorStatus)
                {
                    doorStatus = true;
                    recordTime = DateTime.Now;
                    PortHelper.SendCommand(comPort, OpenCommand);
                    SetTitle set = new SetTitle(setTitle);
                    this.Invoke(set, new object[] { "开" });
                }
                bool add = false;
                List<AccessRecordApiDto> dtos = new List<AccessRecordApiDto>();
                for (var i = 0; i < findList.Count; i++)
                {
                    if (userList.FirstOrDefault(c => c.Id == findList[i].Id) != null)
                        continue;
                    if (userList.Count == 4)
                        userList.RemoveAt(3);
                    findList[i].FindTime = DateTime.Now;
                    userList.Insert(0, findList[i]);
                    add = true;
                    image = findList[i].ImagePath;
                    dtos.Add(new AccessRecordApiDto() { UserId = findList[i].Id, UserType = findList[i].UserType, Similar = similars[i] });
                }
                if (add)
                {
                    delegateRefresh del = new delegateRefresh(RefreshForm);
                    this.Invoke(del, null);
                    recordTime = DateTime.Now;
                    string base64 = ImageHelper.GetBase64FromImage(bitmap);
                    Task.Run(() =>
                     {
                         BatchAccessRecord batchModel = new BatchAccessRecord();
                         batchModel.Base64 = base64;
                         batchModel.AccessRecords = dtos;
                         batchModel.MobileId = deviceInfo.Id;
                         batchModel.TurnOver = deviceInfo.TurnOver;
                         AjaxResult result = WWebClientHelper.HttpPost<AjaxResult>(WWebClientHelper.SaveBatchAccessRecordApiString, WWebClientHelper.GetJson<BatchAccessRecord>(batchModel));

                     });
                }
            }
            catch (Exception ex)
            {
                FileHelper.WriteFile("D:/1.txt", ex.Message);
            }

        }


        void RefreshForm()
        {
            if (image != "")
            {
                pictureBox1.Image = System.Drawing.Image.FromFile(dicPath + image);
            }
        }
        /// <summary>
        /// 适应大小
        /// </summary>
        private void initWindows()
        {
            int count = this.Controls.Count * 2 + 2;
            float[] factor = new float[count];
            int i = 0;
            factor[i++] = Size.Width;
            factor[i++] = Size.Height;
            foreach (Control ctrl in this.Controls)
            {
                factor[i++] = ctrl.Location.X / (float)Size.Width;
                factor[i++] = ctrl.Location.Y / (float)Size.Height;
                ctrl.Tag = ctrl.Size;
            }
            Tag = factor;
        }
        void GetUserInit()
        {
            LoadingControl pLoading = LoadingControl.getLoading();
            pLoading.SetExecuteMethod(method);
            pLoading.ShowDialog();
        }
        WebClient client;
        private void method()
        {
            LoadingControl pLoading = LoadingControl.getLoading();
            client = new WebClient();
            try
            {
                SynsInputP synsIn = new SynsInputP() { MobileId = deviceInfo.Id, PageSize = 10, PageIndex = 1 };
                AjaxResult<SynsOput> syns = WWebClientHelper.HttpPost<AjaxResult<SynsOput>>(WWebClientHelper.SynsApiString, WWebClientHelper.GetJson<SynsInputP>(synsIn));
                if (syns.data.DeleteUserIds != null && syns.data.DeleteUserIds.Count > 0)
                {
                    compare.Delete(syns.data.DeleteUserIds, dicPath);
                }
                if (syns.data.DeleteVisitors != null && syns.data.DeleteVisitors.Count > 0)
                {
                    compare.Delete(syns.data.DeleteVisitors, dicPath);
                }
                int total = syns.data.TotolPage;
                if (syns.data.UserInfoSynsOputs != null)
                {
                    foreach (var user in syns.data.UserInfoSynsOputs)
                    {
                        if (System.IO.File.Exists(dicPath + "/" + user.UserId + ".jpg"))
                        {
                            System.IO.File.Delete(dicPath + "/" + user.UserId + ".jpg");
                        }
                        try
                        {
                            client.DownloadFile(WWebClientHelper.BaseApi + user.HeadUrl, dicPath + "/" + user.UserId + ".jpg");
                        }
                        catch (Exception ex)
                        {
                            SaveSyncErrorInput syncError = new SaveSyncErrorInput() { ErrorMessage = ex.Message, ErrorType = 0, MobileId = deviceInfo.Id, OperateType = 0, UserId = user.UserId, UserType = 0 };
                            WWebClientHelper.HttpPost<AjaxResult<SynsOput>>(WWebClientHelper.SaveSaveSyncErrorApiString, WWebClientHelper.GetJson<SaveSyncErrorInput>(syncError));
                            continue;
                        }
                        bool result = compare.Register(new CZUserInfo() { Id = user.UserId, Name = user.NickName, ImagePath = "/" + user.UserId + ".jpg", FindTime = DateTime.Now }, dicPath);
                        if (!result)
                        {
                            SaveSyncErrorInput syncError = new SaveSyncErrorInput() { ErrorMessage = "", ErrorType = 1, MobileId = deviceInfo.Id, OperateType = 0, UserId = user.UserId, UserType = 0 };
                            WWebClientHelper.HttpPost<AjaxResult<SynsOput>>(WWebClientHelper.SaveSaveSyncErrorApiString, WWebClientHelper.GetJson<SaveSyncErrorInput>(syncError));
                        }
                        pLoading.SetCaptionAndDescription("", "", "执行进度" + 0 + "/" + total);

                    }
                }
                for (var i = 1; i < syns.data.TotolPage; i++)
                {
                    synsIn = new SynsInputP() { MobileId = deviceInfo.Id, PageSize = 10, PageIndex = i + 1 };
                    syns = WWebClientHelper.HttpPost<AjaxResult<SynsOput>>(WWebClientHelper.SynsApiString, WWebClientHelper.GetJson<SynsInputP>(synsIn));
                    foreach (var user in syns.data.UserInfoSynsOputs)
                    {
                        try
                        {
                            if (System.IO.File.Exists(dicPath + "/" + user.UserId + ".jpg"))
                            {
                                System.IO.File.Delete(dicPath + "/" + user.UserId + ".jpg");
                            }
                            client.DownloadFile(WWebClientHelper.BaseApi + user.HeadUrl, dicPath + "/" + user.UserId + ".jpg");
                            bool result = compare.Register(new CZUserInfo() { Id = user.UserId, Name = user.NickName, ImagePath = "/" + user.UserId + ".jpg", FindTime = DateTime.Now }, dicPath);
                            if (!result)
                            {
                                SaveSyncErrorInput syncError = new SaveSyncErrorInput() { ErrorMessage = "", ErrorType = 1, MobileId = deviceInfo.Id, OperateType = 0, UserId = user.UserId, UserType = 0 };
                                WWebClientHelper.HttpPost<AjaxResult<SynsOput>>(WWebClientHelper.SaveSaveSyncErrorApiString, WWebClientHelper.GetJson<SaveSyncErrorInput>(syncError));

                            }
                            pLoading.SetCaptionAndDescription("", "", "执行进度" + i + "/" + total);
                        }
                        catch (Exception ex)
                        {
                            SaveSyncErrorInput syncError = new SaveSyncErrorInput() { ErrorMessage = ex.Message, ErrorType = 0, MobileId = deviceInfo.Id, OperateType = 0, UserId = user.UserId, UserType = 0 };
                            WWebClientHelper.HttpPost<AjaxResult<SynsOput>>(WWebClientHelper.SaveSaveSyncErrorApiString, WWebClientHelper.GetJson<SaveSyncErrorInput>(syncError));
                            continue;
                        }
                    }
                }
                if (syns.data.VisitorSynsOputs != null)
                {
                    foreach (var visitor in syns.data.VisitorSynsOputs)
                    {
                        try
                        {
                            if (System.IO.File.Exists(dicPath + "/" + visitor.VisitorId + ".jpg"))
                            {
                                System.IO.File.Delete(dicPath + "/" + visitor.VisitorId + ".jpg");
                            }
                            client.DownloadFile(WWebClientHelper.BaseApi + visitor.HeadUrl, dicPath + "/" + visitor.VisitorId + ".jpg");
                            bool result = compare.Register(new CZUserInfo() { Id = visitor.VisitorId, Name = visitor.Name, ImagePath = "/" + visitor.VisitorId + ".jpg", FindTime = DateTime.Now, UserType = 1 }, dicPath);
                            if (!result)
                            {
                                SaveSyncErrorInput syncError = new SaveSyncErrorInput() { ErrorMessage = "", ErrorType = 1, MobileId = deviceInfo.Id, OperateType = 0, UserId = visitor.VisitorId, UserType = 1 };
                                WWebClientHelper.HttpPost<AjaxResult<SynsOput>>(WWebClientHelper.SaveSaveSyncErrorApiString, WWebClientHelper.GetJson<SaveSyncErrorInput>(syncError));

                            }
                            pLoading.SetCaptionAndDescription("", "", "执行进度" + 0 + "/" + total);

                        }
                        catch (Exception ex)
                        {
                            SaveSyncErrorInput syncError = new SaveSyncErrorInput() { ErrorMessage = ex.Message, ErrorType = 0, MobileId = deviceInfo.Id, OperateType = 0, UserId = visitor.VisitorId, UserType = 1 };
                            WWebClientHelper.HttpPost<AjaxResult<SynsOput>>(WWebClientHelper.SaveSaveSyncErrorApiString, WWebClientHelper.GetJson<SaveSyncErrorInput>(syncError));
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                //  MessageBox.Show(ex.Message);
            }
            SynsInput synsOK = new SynsInput() { MobileId = deviceInfo.Id };
            AjaxResult deleteResult = WWebClientHelper.HttpPost<AjaxResult<SynsOput>>(WWebClientHelper.SynsSuccessApiString, WWebClientHelper.GetJson<SynsInput>(synsOK));
            compare.Reload();
            LoadingControl.getLoading().CloseLoadingForm();

        }
    }
}
